grammar SpiderDefinition;

transform:
	nameDef
	(headersDef
	| paramsDef
	| paramsGeneratorDef
	| bodyGeneratorDef
	| settingsDef)*
	taskDef+
	;

nameDef:
    NAME '->' STRING
;

urlDef:
    URL '->' STRING
;

methodDef:
    METHOD '->' STRING
;

headersDef:
    HEADERS pair* END
;

paramsDef:
    PARAMS pair* END
;

paramsGeneratorDef:
    PARAMS_GENERATOR pair* END
;

bodyDef:
    BODY STRING END
;

bodyGeneratorDef:
    BODY_GENERATOR STRING END
;

settingsDef:
    SETTINGS pair* END
;

taskDef:
   TASK
   nameDef
   urlDef
   methodDef
   (paramsDef
   | headersDef
   | settingsDef
   | bodyDef
   | onstartDef
   | onfinishDef
   | onresultDef
   | collectsDef
   | subtasksDef)*
   subtasksGeneratorDef*
   END
;

onstartDef:
   ONSTART STRING END
;

onresultDef:
   ONRESULT ((retryDef retryTimesDef? processDef) | processDef) END
;

retryDef:
    RETRY_WHEN '->' STRING
;

retryTimesDef:
    RETRY_TIMES '->' INT
;

processDef:
    PROCESS '->' STRING
;

onfinishDef:
    ONFINISH STRING END
;

collectsDef:
    COLLECTS pair* END
;
subtasksDef:
    SUBTASKS STRING (',' STRING)* END
;

subtasksGeneratorDef:
    SUBTASKS_GENERATOR
    nameDef
    nextDef?
    (onstartDef
    | onresultDef
    | onfinishDef
    | collectsDef)* 
    STRING
    END
;

nextDef:
    NEXT '->' STRING (',' STRING)*
;

pair:
    STRING '->' (STRING | INT)
;

NAME: 'name';
URL: 'url';
METHOD: 'method';
HEADERS: 'headers';
PARAMS: 'params';
PARAMS_GENERATOR: 'params_generator';
BODY: 'body';
BODY_GENERATOR: 'body_generator';
SETTINGS: 'settings';
TASK: 'taskdef';
ONSTART: 'onstart';
ONRESULT: 'onresult';
RETRY_TIMES: 'retry_times';
RETRY_WHEN: 'retry_when';
PROCESS: 'process';
ONFINISH: 'onfinish';
COLLECTS: 'collects';
SUBTASKS:
    'subtasks'
    ;
SUBTASKS_GENERATOR:
    'subtasks_generator'
    ;

NEXT:
    'next'
;
END:
    'end'
    ;
STRING
    :   '\'\'\'' TRIAPOS*? '\'\'\''
    |'"' ( ESC | ~('"'|'\r'|'\n') )*? '"'
    |   '\'' ( ESC | ~('\''|'\r'|'\n') )*? '\''
    ;

INT
    :
       '0'..'9'+
    ;

fragment
TRIAPOS
    : '\''? '\''? (ESC|~('\''))+
    ;

fragment
ESC :   '\\' ([abtnfrv]|'"'|'\'')
    |   UNICODE_ESCAPE
    |   HEX_ESCAPE
    |   OCTAL_ESCAPE
    ;

fragment
UNICODE_ESCAPE
    :   '\\' 'u' HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT
    ;

fragment
OCTAL_ESCAPE
    :   '\\' [0-3] [0-7] [0-7]
    |   '\\' [0-7] [0-7]
    |   '\\' [0-7]
    ;

fragment
HEX_ESCAPE
    :   '\\' HEXDIGIT HEXDIGIT?
    ;

fragment
HEXDIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

COMMENT :   '#' .*? '\r'? '\n' -> skip ;
// Match both UNIX and Windows newlines
NL      :   '\r'? '\n' -> skip;
WS      :   [ \t]+ -> skip ;